home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 17
/
CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso
/
CUCD
/
Programming
/
DiceSource
/
src
/
fsovl
/
core.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-09-09
|
12KB
|
520 lines
/*
* (c)Copyright 1992-1997 Obvious Implementations Corp. Redistribution and
* use is allowed under the terms of the DICE-LICENSE FILE,
* DICE-LICENSE.TXT.
*/
/*
* CORE.C - core overlay routines
*/
#include "defs.h"
Prototype void InitCore(void);
Prototype GEntry *MakeGEntry(GEntry *groot, char *path, short len, long mode);
Prototype GHandle *MakeGHandle(GEntry *gentry, long mode);
Prototype void FreeGHan(GHandle *ghan);
Prototype void FreeGEntry(GEntry *gentry, long mode);
Prototype void FixFileInfo(FileInfoBlock *fib);
Prototype void SetGEntry(GEntry *gentry, FileInfoBlock *fib);
Prototype long WriteDataGEntry(GEntry *gentry,long pos, char *buf, long bytes);
Prototype long ReadDataGEntry(GEntry *gentry,long pos, char *buf, long bytes);
GEntry *AllocGEntry(GEntry *par, long lock, char *ptr, short len);
short NextSegment(char **pptr, short *plen, char *path, short len);
Prototype GEntry GRoot;
Prototype long LockRefs;
GEntry GRoot;
long LockRefs;
void
InitCore()
{
GRoot.ge_Node.ln_Name = DevName;
GRoot.ge_LCRefs = 1;
GRoot.ge_Flags |= GEF_DIRECTORY;
NewList(&GRoot.ge_List);
}
/*
* Core of the system
*/
GEntry *
MakeGEntry(GEntry *groot, char *path, short len, long mode)
{
char *sptr = path;
short slen = 0;
short softRootFlag = 0;
GEntry *gsoftlink = NULL;
++groot->ge_LCRefs;
++LockRefs;
while (groot && NextSegment(&sptr, &slen, path, len)) {
GEntry *gnew;
// ignore device spec (total garbage because assignment specs
// would also be there). However, use the colon for softlinks
if (sptr[slen-1] == ':' && softRootFlag == 0)
continue;
if (groot == &GRoot || softRootFlag) {
/*
* Device specified, set to root if for us else look for the
* device and lock it's root.
*/
short sslen = slen;
if (sptr[slen-1] == '/' || sptr[slen-1] == ':')
--sslen;
dbprintf(("segment %.*s\n", sslen, sptr));
gnew = GetHead(&GRoot.ge_List);
while (gnew) {
if ((ubyte)gnew->ge_Node.ln_Name[0] == sslen) {
if (strnicmp(gnew->ge_Node.ln_Name + 1, sptr, sslen) == 0)
break;
}
gnew = GetSucc(&gnew->ge_Node);
}
if (gnew == NULL) {
MsgPort *port;
BPTR lock;
if (port = FindDosDevice(sptr, sslen, &lock)) {
if (port == PktPort) {
gnew = &GRoot;
} else {
if (lock == 0)
lock = LockPacketPort(port, "", 0);
if (lock) {
gnew = AllocGEntry(&GRoot, lock, sptr, sslen);
gnew->ge_Flags |= GEF_DIRECTORY;
}
}
}
}
} else if (slen == 1 && sptr[0] == '/') {
/*
* Back one directory
*/
if ((gnew = groot->ge_Parent) == NULL)
gnew = &GRoot;
} else {
/*
* Directory or file element
*/
short sslen = (sptr[slen-1] == '/') ? slen - 1 : slen;
gnew = GetHead(&groot->ge_List);
while (gnew) {
if ((ubyte)gnew->ge_Node.ln_Name[0] == sslen) {
if (strnicmp(gnew->ge_Node.ln_Name + 1, sptr, sslen) == 0)
break;
}
gnew = GetSucc(&gnew->ge_Node);
}
if (gnew == NULL && groot != &GRoot) {
long lock;
/*
* the last element may not exist for modes 1006 so we
* create an entry anyway with a lock field of 0. If
* the open fails later on, the entry will be deleted
*/
if (sptr + slen == path + len && mode == 1006) {
gnew = AllocGEntry(groot, 0, sptr, sslen);
} else if (lock = LockPacket(groot->ge_Lock, sptr, sslen)) {
__aligned FileInfoBlock fib;
fib.fib_Size = 0;
ExaminePacket(lock, &fib);
gnew = AllocGEntry(groot, lock, sptr, sslen);
if (gnew)
SetGEntry(gnew, &fib);
}
}
}
softRootFlag = 0;
if (gnew) {
++gnew->ge_LCRefs;
++LockRefs;
// If we encountered a softlink the above reference is
// left for gsoftlink and we follow the softlink relative
// to the previous directory instead of relative to the gnew
// lock.
if (gnew->ge_SoftLink) {
if (gsoftlink)
FreeGEntry(gsoftlink, 1005);
gsoftlink = gnew;
path = gnew->ge_SoftLink;
len = strlen(gnew->ge_SoftLink);
sptr = path;
slen = 0;
if (strchr(path, ':'))
softRootFlag = 1;
gnew = groot;
++groot->ge_LCRefs;
++LockRefs;
}
}
FreeGEntry(groot, 1005);
groot = gnew;
}
if (gsoftlink)
FreeGEntry(gsoftlink, 1005);
return(groot);
}
GEntry *
AllocGEntry(GEntry *gparent, long lock, char *sptr, short slen)
{
GEntry *gentry;
if (gentry = AllocMem(sizeof(GEntry) + slen + 1, MEMF_PUBLIC|MEMF_CLEAR)) {
if (GetHead(&gparent->ge_List) == NULL) {
++gparent->ge_LCRefs;;
++LockRefs;
}
AddTail(&gparent->ge_List, &gentry->ge_Node);
NewList(&gentry->ge_List);
gentry->ge_Parent = gparent;
gentry->ge_Lock = lock;
gentry->ge_Node.ln_Name = (char *)(gentry + 1);
gentry->ge_Node.ln_Name[0] = slen;
movmem(sptr, gentry->ge_Node.ln_Name + 1, slen);
}
return(gentry);
}
GHandle *
MakeGHandle(GEntry *gentry, long mode)
{
GHandle *ghan;
BPTR fh;
short error = 0;
if (ghan = AllocMem(sizeof(GHandle), MEMF_PUBLIC|MEMF_CLEAR)) {
/*
* Initialize handle
*/
ghan->gh_Mode = mode;
ghan->gh_GEntry = gentry;
/*
* Bump gentry FHRefs, if going from 0->1 decompress and load file
*/
if (gentry->ge_FHRefs++ == 0) {
++gentry->ge_LCRefs;
++LockRefs;
dbprintf(("Decomp: open\n"));
if (mode == 1006) {
if (gentry->ge_Lock == 0) {
ubyte *name = gentry->ge_Node.ln_Name + 1;
short len = name[-1];
BPTR plock = gentry->ge_Parent->ge_Lock;
if (fh = OpenPacket(plock, name, len, 1006)) {
ClosePacket(fh);
gentry->ge_Lock = LockPacket(plock, name, len);
} else {
error = 1;
}
} else {
error = 1;
}
}
}
}
if (error) {
FreeGHan(ghan);
ghan = NULL;
}
return(ghan);
}
long
ReadDataGEntry(GEntry *gentry, long pos, char *buf, long bytes)
{
long n = 0;
if (pos >= 0 && pos < gentry->ge_Bytes) {
/*
* If not cached we must read the file, but only allocate a cache
* if the reader is reading less then the file size. This optimizes
* whole-file reads in two ways: (1) no intermediate buffer is
* allocated which saves memory and (2) we read/decompress directly
* to the reader's buffer.
*/
if ((gentry->ge_Flags & GEF_CACHED) == 0) {
BPTR fh;
if (fh = OpenPacket(gentry->ge_Lock, "", 0, 1005)) {
if (pos == 0 && bytes >= gentry->ge_Bytes) {
dbprintf(("READ: DIRECT %d\n", bytes));
if (gentry->ge_Flags & GEF_COMPRESSED)
DeCompress(fh, buf, gentry->ge_Bytes);
else
ReadPacket(fh, buf, gentry->ge_Bytes);
n = gentry->ge_Bytes;
} else {
dbprintf(("READ: CACHELD %d\n", gentry->ge_Bytes));
gentry->ge_Buf = AllocMem(gentry->ge_Bytes+1,MEMF_PUBLIC);
if (gentry->ge_Buf) {
if (gentry->ge_Flags & GEF_COMPRESSED)
DeCompress(fh, gentry->ge_Buf, gentry->ge_Bytes);
else
ReadPacket(fh, gentry->ge_Buf, gentry->ge_Bytes);
gentry->ge_Max = gentry->ge_Bytes + 1;
gentry->ge_Flags |= GEF_CACHED;
}
}
ClosePacket(fh);
}
}
/*
* Copy data from cache
*/
if (gentry->ge_Flags & GEF_CACHED) {
n = gentry->ge_Bytes - pos;
if (n > bytes)
n = bytes;
movmem(gentry->ge_Buf + pos, buf, n);
dbprintf(("READ: CACHED %d\n", bytes));
}
}
return(n);
}
long
WriteDataGEntry(GEntry *gentry, long pos, char *buf, long bytes)
{
long n = -ERROR_NO_FREE_STORE;
/*
* If file is not cached and not empty we have to cache what we have
* first!
*/
if ((gentry->ge_Flags & GEF_CACHED) == 0 && gentry->ge_Bytes) {
BPTR fh;
if (fh = OpenPacket(gentry->ge_Lock, "", 0, 1005)) {
gentry->ge_Buf = AllocMem(gentry->ge_Bytes,MEMF_PUBLIC);
if (gentry->ge_Buf) {
if (gentry->ge_Flags & GEF_COMPRESSED)
DeCompress(fh, gentry->ge_Buf, gentry->ge_Bytes);
else
ReadPacket(fh, gentry->ge_Buf, gentry->ge_Bytes);
gentry->ge_Max = gentry->ge_Bytes;
gentry->ge_Flags |= GEF_CACHED;
}
ClosePacket(fh);
}
}
/*
* Extend buffer if necessary
* Copy data in
*/
/* printf("before pos %d bytes %d gentry %d/%d\n", pos, bytes, gentry->ge_Bytes, gentry->ge_Max); */
{
long cbytes = pos + bytes;
if (cbytes > gentry->ge_Max) {
ubyte *xbuf;
if (xbuf = AllocMem(cbytes + (cbytes >> 1), MEMF_PUBLIC)) {
movmem(gentry->ge_Buf, xbuf, gentry->ge_Bytes);
if (gentry->ge_Max)
FreeMem(gentry->ge_Buf, gentry->ge_Max);
gentry->ge_Buf = xbuf;
gentry->ge_Max = cbytes + (cbytes >> 1);
}
}
if (cbytes <= gentry->ge_Max) {
movmem(buf, gentry->ge_Buf + pos, bytes);
n = bytes;
if (cbytes > gentry->ge_Bytes)
gentry->ge_Bytes = cbytes;
gentry->ge_Flags |= GEF_DIRTY | GEF_CACHED;
}
}
/* printf("after pos %d bytes %d gentry %d/%d\n", pos, bytes, gentry->ge_Bytes, gentry->ge_Max); */
return(n);
}
void
FreeGHan(GHandle *ghan)
{
GEntry *gentry = ghan->gh_GEntry;
/*
* Decrement gentry FHRefs. If 0 and buffer is dirty, compress and
* write out buffer. If buffer is not dirty simply free the memory.
*/
if (--gentry->ge_FHRefs == 0)
FreeGEntry(gentry, ghan->gh_Mode);
ghan->gh_GEntry = NULL;
FreeMem(ghan, sizeof(GHandle));
}
void
FreeGEntry(GEntry *gentry, long mode)
{
--LockRefs;
if (--gentry->ge_LCRefs == 0) {
GEntry *gparent = gentry->ge_Parent;
if (gentry->ge_Lock)
UnLockPacket(gentry->ge_Lock);
gentry->ge_Lock = 0;
Remove(&gentry->ge_Node);
if (gentry->ge_Flags & GEF_DIRTY) {
BPTR fh;
fh = OpenPacket(
gparent->ge_Lock,
gentry->ge_Node.ln_Name + 1,
(ubyte)gentry->ge_Node.ln_Name[0],
1006
);
if (fh) {
if (Compress(fh, gentry->ge_Buf, gentry->ge_Bytes))
gentry->ge_Flags |= GEF_COMPRESSED;
else
gentry->ge_Flags &= ~GEF_COMPRESSED;
ClosePacket(fh);
SetCommentPacket(
gparent->ge_Lock,
gentry->ge_Node.ln_Name + 1,
(ubyte)gentry->ge_Node.ln_Name[0],
"",
0,
gentry
);
}
gentry->ge_Flags &= ~GEF_DIRTY;
}
if (gentry->ge_Buf)
FreeMem(gentry->ge_Buf, gentry->ge_Max);
gentry->ge_Buf = NULL;
gentry->ge_Max = 0;
if (gentry->ge_SoftLink) {
FreeMem(gentry->ge_SoftLink, strlen(gentry->ge_SoftLink) + 1);
gentry->ge_SoftLink = NULL;
}
FreeMem(gentry, sizeof(GEntry)+(ubyte)gentry->ge_Node.ln_Name[0]+1);
if (GetHead(&gparent->ge_List) == NULL) {
FreeGEntry(gparent, 1005);
}
}
}
/*
* Use comment field to determine file size. Look for
* ##%08lx##
*/
void
FixFileInfo(FileInfoBlock *fib)
{
ubyte len = (ubyte)fib->fib_Comment[0];
if (len >= 12) {
if (fib->fib_Comment[1] == '#'
&& fib->fib_Comment[2] == '#'
&& fib->fib_Comment[11] == '#'
&& fib->fib_Comment[12] == '#') {
/*
* Actual file size after decompression
*/
fib->fib_Size = strtol(fib->fib_Comment + 3, NULL, 16);
/*
* Make comment prefix invisible
*/
movmem(fib->fib_Comment + 13, fib->fib_Comment + 1, len - 12 + 1);
fib->fib_Comment[0] -= 12;
}
}
}
void
SetGEntry(GEntry *gentry, FileInfoBlock *fib)
{
if (fib->fib_DirEntryType > 0)
gentry->ge_Flags |= GEF_DIRECTORY;
fib->fib_Comment[1+(ubyte)fib->fib_Comment[0]] = 0;
if ((ubyte)fib->fib_Comment[0] >= 12) {
if (fib->fib_Comment[1] == '#'
&& fib->fib_Comment[2] == '#'
&& fib->fib_Comment[11] == '#'
&& fib->fib_Comment[12] == '#') {
fib->fib_Size = strtol(fib->fib_Comment + 3, NULL, 16);
gentry->ge_Flags |= GEF_COMPRESSED;
}
}
gentry->ge_Bytes = fib->fib_Size;
if (gentry->ge_SoftLink) {
FreeMem(gentry->ge_SoftLink, strlen(gentry->ge_SoftLink) + 1);
gentry->ge_SoftLink = NULL;
}
{
char *sl;
if (sl = strstr(fib->fib_Comment + 1, "SOFTLINK=")) {
sl += 9;
gentry->ge_SoftLink = AllocMem(strlen(sl) + 1, MEMF_PUBLIC);
strcpy(gentry->ge_SoftLink, sl);
}
}
}
short
NextSegment(char **pptr, short *plen, char *path, short len)
{
char *ptr;
char *pathEnd = path + len;
*pptr += *plen;
for (ptr = *pptr; ptr < pathEnd; ++ptr) {
if (*ptr == '/' || *ptr == ':') {
++ptr;
break;
}
}
*plen = ptr - *pptr;
if (*plen == 0)
return(0);
return(1);
}